:art: MQTT

huangqimin001 3 years ago
parent
commit
ff8c710766

+ 63 - 0
api/eqpt_views.py

@@ -170,6 +170,7 @@ def upload_temperature(request):
170 170
     try:
171 171
         eqpt = ThermometerEquipmentInfo.objects.get(macid=macid, status=True)
172 172
     except ThermometerEquipmentInfo.DoesNotExist:
173
+        ThermometerMeasureLogInfo.objects.create(point_id=eqpt.point_id, macid=macid, name=name, sex=sex, birth_stamp=birth_stamp, phone=phone, start_stamp=start_stamp, end_stamp=end_stamp, temperature=temperature, upload_temperature_info=request.POST, status=False)
173 174
         return response(ThermometerEquipmentStatusCode.THERMOMETER_EQUIPMENT_NOT_FOUND)
174 175
 
175 176
     try:
@@ -196,3 +197,65 @@ def upload_temperature(request):
196 197
         })
197 198
 
198 199
     return response()
200
+
201
+
202
+def mqtt_upload_temperature(payload):
203
+    # Received `{"mac":"A4DA324E7A63","pkt":"215","chg_sta":true,"bat":"100","raw_temp":"4697,4696,4697","sta":"0","alg_temp":"4697,4696,4697","alg_gstr":0,"ble_rssi":-21,"wifi_rssi":-68,"current_time":"2021-08-08 15:22:59"}` from `esp/240AC4D3C1AC` topic
204
+    #
205
+    # {
206
+    #     "mac": "A4DA324E7A63",  # 体温贴 mac,固定 6 个字节,12 个字符
207
+    #     "pkt": "215",  # 广播包包序为 85,有效包序范围[1, 255]
208
+    #     "chg_sta": true,  # 充电状态,true 充电,false 未充电
209
+    #     "bat": "100",  # 电量剩余 65%,有效电量范围[0, 100]
210
+    #     "raw_temp": "4697,4696,4697",  # 三个原始温度数
211
+    #     "sta": "0",  # 算法返回状态
212
+    #     "alg_temp": "4697,4696,4697",  # 算法返回三个温度
213
+    #     "alg_gstr": 0,  # 算法手臂姿态
214
+    #     "ble_rssi": -21,  # 体温贴相对于底座的信号强度
215
+    #     "wifi_rssi": -68,  # 底座网络信号强度
216
+    #     "current_time": "2021-08-08 15:22:59"  # 底座接收到体温贴信息的实时时间
217
+    # }
218
+    try:
219
+        payload = json.loads(payload)
220
+    except Exception:
221
+        return
222
+
223
+    macid = payload.get('mac', '')
224
+    macid = f'{macid[:2]}:{macid[2:4]}:{macid[4:6]}:{macid[6:8]}:{macid[8:10]}:{macid[10:12]}'
225
+    current_time = payload.get('current_time', '')
226
+    start_stamp = end_stamp = tc.string_to_timestamp(current_time)
227
+    # raw_temp = payload.get('raw_temp', '')
228
+    alg_temp = payload.get('alg_temp', '')
229
+
230
+    # temp = raw_temp.split(',') + alg_temp.split(',')
231
+    temp = alg_temp.split(',')
232
+    temp = [int(t) for t in temp if t]
233
+
234
+    if not temp:
235
+        return
236
+
237
+    temperature = max(temp) / 100
238
+
239
+    try:
240
+        eqpt = ThermometerEquipmentInfo.objects.get(macid=macid, status=True)
241
+    except ThermometerEquipmentInfo.DoesNotExist:
242
+        ThermometerMeasureLogInfo.objects.create(macid=macid, start_stamp=start_stamp, end_stamp=end_stamp, temperature=temperature, temperature_src=ThermometerMeasureLogInfo.MQTT, upload_temperature_info=payload, status=False)
243
+        return
244
+
245
+    try:
246
+        point = IsolationPointInfo.objects.get(point_id=eqpt.point_id, status=True)
247
+    except IsolationPointInfo.DoesNotExist:
248
+        return
249
+
250
+    point_measure_ymd = tc.local_string(format='%Y-%m-%d')
251
+    point_measure_window = point.current_measure_window
252
+
253
+    eqpt.last_submit_at = tc.utc_datetime()
254
+    eqpt.save()
255
+
256
+    ThermometerMeasureLogInfo.objects.create(point_id=eqpt.point_id, macid=macid, start_stamp=start_stamp, end_stamp=end_stamp, temperature=temperature, temperature_src=ThermometerMeasureLogInfo.MQTT, upload_temperature_info=payload)
257
+
258
+    if point_measure_window:
259
+        ThermometerMeasureInfo.objects.update_or_create(point_id=eqpt.point_id, point_measure_ymd=point_measure_ymd, point_measure_window=point_measure_window, macid=macid, defaults={
260
+            'temperature': temperature,
261
+        })

+ 106 - 0
commands/management/commands/mqtt.py

@@ -0,0 +1,106 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+import logging
4
+import random
5
+import time
6
+
7
+from django_six import CompatibilityBaseCommand
8
+from paho.mqtt import client as mqtt_client
9
+from api.eqpt_views import mqtt_upload_temperature
10
+
11
+
12
+logger = logging.getLogger('console')
13
+
14
+
15
+# defined(PRORON_MQTT_DOMESTIC_SERVER)
16
+# define MQTT_SERVER_TYPE    MQTT_SERVER_TYPE_DOMAIN_NAME
17
+# define MQTT_BROKER_URI    "china.mqtt.protontek.com"         /* Domestic server "47.100.92.19" */
18
+# define MQTT_USERNAME       "proton"
19
+# define MQTT_PASSWORD       "proton123"
20
+# define MQTT_PORT      1883
21
+broker = 'china.mqtt.protontek.com'
22
+username = 'proton'
23
+password = 'proton123'
24
+port = 1883
25
+topic = 'esp/#'
26
+client_id = f'python-mqtt-{random.randint(0, 1000)}'
27
+
28
+
29
+# MQTT连接
30
+def connect_mqtt():
31
+    def on_connect(client, userdata, flags, rc):
32
+        if rc == 0:
33
+            print('Connected to MQTT Broker')
34
+        else:
35
+            print('Failed to connect, return code %d\n', rc)
36
+    # Set Connecting Client ID
37
+    print(f'Connected to MQTT Broker by client_id `{client_id}`')
38
+    client = mqtt_client.Client(client_id)
39
+    client.username_pw_set(username, password=password)
40
+    client.on_connect = on_connect
41
+    client.connect(broker, port)
42
+    return client
43
+
44
+
45
+# MQTT发布消息
46
+# from commands.management.commands.mqtt import publish_run
47
+# publish_run()
48
+def publish(client):
49
+    msg_count = 0
50
+    while True:
51
+        time.sleep(1)
52
+        msg = f'messages: `{msg_count}`'
53
+        result = client.publish(topic, msg)
54
+        # result: [0, 1]
55
+        status = result[0]
56
+        if status == 0:
57
+            print(f'Send `{msg}` to topic `{topic}`')
58
+        else:
59
+            print(f'Failed to send message to topic {topic}')
60
+        msg_count += 1
61
+
62
+
63
+def publish_run():
64
+    client = connect_mqtt()
65
+    client.loop_start()
66
+    publish(client)
67
+
68
+
69
+# MQTT订阅消息
70
+def subscribe(client: mqtt_client):
71
+    def on_message(client, userdata, msg):
72
+        # Received `{"mac":"A4DA324E7A63","pkt":"215","chg_sta":true,"bat":"100","raw_temp":"4697,4696,4697","sta":"0","alg_temp":"4697,4696,4697","alg_gstr":0,"ble_rssi":-21,"wifi_rssi":-68,"current_time":"2021-08-08 15:22:59"}` from `esp/240AC4D3C1AC` topic
73
+        #
74
+        # {
75
+        #     "mac": "A4DA324E7A63",  # 体温贴 mac,固定 6 个字节,12 个字符
76
+        #     "pkt": "215",  # 广播包包序为 85,有效包序范围[1, 255]
77
+        #     "chg_sta": true,  # 充电状态,true 充电,false 未充电
78
+        #     "bat": "100",  # 电量剩余 65%,有效电量范围[0, 100]
79
+        #     "raw_temp": "4697,4696,4697",  # 三个原始温度数
80
+        #     "sta": "0",  # 算法返回状态
81
+        #     "alg_temp": "4697,4696,4697",  # 算法返回三个温度
82
+        #     "alg_gstr": 0,  # 算法手臂姿态
83
+        #     "ble_rssi": -21,  # 体温贴相对于底座的信号强度
84
+        #     "wifi_rssi": -68,  # 底座网络信号强度
85
+        #     "current_time": "2021-08-08 15:22:59"  # 底座接收到体温贴信息的实时时间
86
+        # }
87
+        payload = msg.payload.decode()
88
+        print(f'Received `{payload}` from `{msg.topic}` topic')
89
+        mqtt_upload_temperature(payload)
90
+
91
+    client.subscribe(topic)
92
+    client.on_message = on_message
93
+
94
+
95
+def subscribe_run():
96
+    client = connect_mqtt()
97
+    subscribe(client)
98
+    client.loop_forever()
99
+
100
+
101
+class Command(CompatibilityBaseCommand):
102
+    def handle(self, *args, **options):
103
+
104
+        logger.info('MQTT client is dealing')
105
+
106
+        subscribe_run()

+ 2 - 2
equipment/admin.py

@@ -22,8 +22,8 @@ class ThermometerMeasureInfoAdmin(ReadOnlyModelAdmin, admin.ModelAdmin):
22 22
 
23 23
 
24 24
 class ThermometerMeasureLogInfoAdmin(ReadOnlyModelAdmin, admin.ModelAdmin):
25
-    list_display = ('point_id', 'macid', 'sn', 'name', 'sex', 'birth_stamp', 'phone', 'start_stamp', 'end_stamp', 'temperature', 'status', 'updated_at', 'created_at')
26
-    list_filter = ('point_id', 'status')
25
+    list_display = ('point_id', 'macid', 'sn', 'name', 'sex', 'birth_stamp', 'phone', 'start_stamp', 'end_stamp', 'temperature', 'temperature_src', 'status', 'updated_at', 'created_at')
26
+    list_filter = ('point_id', 'temperature_src', 'status')
27 27
 
28 28
 
29 29
 admin.site.register(IsolationPointInfo, IsolationPointInfoAdmin)

+ 18 - 0
equipment/migrations/0005_thermometermeasureloginfo_temperature_src.py

@@ -0,0 +1,18 @@
1
+# Generated by Django 3.2.6 on 2021-08-08 11:03
2
+
3
+from django.db import migrations, models
4
+
5
+
6
+class Migration(migrations.Migration):
7
+
8
+    dependencies = [
9
+        ('equipment', '0004_auto_20210712_0035'),
10
+    ]
11
+
12
+    operations = [
13
+        migrations.AddField(
14
+            model_name='thermometermeasureloginfo',
15
+            name='temperature_src',
16
+            field=models.IntegerField(choices=[(1, '接口回调'), (2, 'MQTT')], default=1, help_text='用户体温来源', verbose_name='temperature_src'),
17
+        ),
18
+    ]

+ 10 - 0
equipment/models.py

@@ -148,6 +148,14 @@ class ThermometerMeasureInfo(BaseModelMixin):
148 148
 
149 149
 
150 150
 class ThermometerMeasureLogInfo(BaseModelMixin):
151
+    CALLBACK = 1
152
+    MQTT = 2
153
+
154
+    TEMPERATURE_SRC_TUPLE = (
155
+        (CALLBACK, '接口回调'),
156
+        (MQTT, 'MQTT'),
157
+    )
158
+
151 159
     point_id = models.CharField(_('point_id'), max_length=32, blank=True, null=True, help_text='隔离点唯一标识', db_index=True)
152 160
 
153 161
     macid = models.CharField(_('macid'), max_length=32, blank=True, null=True, help_text='设备号')
@@ -163,6 +171,8 @@ class ThermometerMeasureLogInfo(BaseModelMixin):
163 171
 
164 172
     temperature = models.FloatField(_('temperature'), default=0, help_text='用户体温')
165 173
 
174
+    temperature_src = models.IntegerField(_('temperature_src'), choices=TEMPERATURE_SRC_TUPLE, default=CALLBACK, help_text='用户体温来源')
175
+
166 176
     upload_temperature_info = models.TextField(_('upload_temperature_info'), blank=True, null=True, help_text='测温结果上传信息')
167 177
 
168 178
     class Meta:

+ 1 - 0
requirements.txt

@@ -2,6 +2,7 @@ StatusCode==1.0.0
2 2
 furl==2.1.2
3 3
 jsonfield==3.1.0
4 4
 mysqlclient==2.0.3
5
+paho-mqtt==1.5.1
5 6
 pysnippets==1.1.4
6 7
 requests==2.25.1
7 8
 rlog==0.3

+ 2 - 2
requirements_deploy.txt

@@ -1,3 +1,3 @@
1
-ipdb==0.13.3
2
-ipython==7.18.1
1
+ipdb==0.13.9
2
+ipython==7.26.0
3 3
 uwsgi==2.0.19.1

+ 2 - 2
requirements_dev.txt

@@ -1,2 +1,2 @@
1
-isort==5.4.2
2
-pycodestyle==2.6.0
1
+isort==5.9.3
2
+pycodestyle==2.7.0

+ 1 - 1
thermometer/settings.py

@@ -305,7 +305,7 @@ DJANGO_SHORT_URL_REDIRECT_URL = ''
305 305
 
306 306
 # Django-We Settings
307 307
 DJANGO_WE_QUOTE_OR_NOT = True
308
-DJANGO_WE_MODEL_DISPLAY_OR_NOT = True
308
+DJANGO_WE_MODEL_DISPLAY_OR_NOT = False
309 309
 # Enable Cookie or not
310 310
 # DJANGO_WE_BASE_REDIRECT_SET_COOKIE = False
311 311
 # DJANGO_WE_USERINFO_REDIRECT_SET_COOKIE = True